%{
    /*
     * Include Files
     */
    #include "blifparse.hpp"
    #include "blif_common.hpp"
    #include "blif_error.hpp"

    #include "blif_lexer.hpp"

%}

/*
 * Options
 */

/* track line numbers*/
%option yylineno

/* No lexing accross files */
%option noyywrap

/* unistd.h doesn't exist on windows */
%option nounistd

/* Avoid unused yyunput function warning */
%option nounput

/* Avoid unused yyinput function warning */
%option noinput

/* isatty() doesn't exist on windows */
%option never-interactive

/* no default rule to echo unrecongaized tokens to output */
%option nodefault

/*%option bison-bridge*/
%option reentrant

/*
 * Use a prefix to avoid name clashes with other
 * flex lexers
 */
%option prefix="blifparse_"

/* Common character classes */
ID_SET [^ \t\r\n\\="]
BACK_SLASH [\\]
WS [ \t]
ENDL (\n|\n\r|\r\n)

/* Special Parser States */
%x LATCH
%x NAMES
%x SO_COVER

/*
 * Symbol Definitions
 */
%%
<*>#.*{ENDL}                    { /* ignore comments, but forward EOL for end of line comments */
                                  return blifparse::Parser::make_EOL();
                                }
^{WS}*{ENDL}                    { /* Ignore blank lines. */ }
\\{ENDL}{WS}*{ENDL}             {
                                  /*
                                   * Do forward end of line if the last line was a continuation.
                                   *
                                   * Some times line continuations are followed by blank lines (which
                                   * are otherwise ignored). In these cases we *do* want to
                                   * forward EOL, so the parser knows the continued line has finished
                                   */
                                  return blifparse::Parser::make_EOL();
                                }
<*>\\{ENDL}                     { /* line continuation (don't forward EOL to parser) */ }
{ENDL}                          {
                                  return blifparse::Parser::make_EOL();
                                }
<*>{WS}+                        { /* skip white space */ }
<*>\.names                      {
                                  /*
                                   * To process the single output cover rows of the names directly as symbols
                                   * (rather than as strings) we use a special lexer state.
                                   */
                                  BEGIN(NAMES);
                                  return blifparse::Parser::make_DOT_NAMES();
                                }
<*>\.latch                      {
                                  /*
                                   * The initial state value of a latch is ambiguous (it chould be
                                   * interpreted as a string or logic value string). So we use
                                   * a special lexer state to capture it.
                                   */
                                  BEGIN(LATCH);
                                  return blifparse::Parser::make_DOT_LATCH();
                                }
<*>\.model                      { BEGIN(INITIAL); return blifparse::Parser::make_DOT_MODEL(); }
<*>\.subckt                     { BEGIN(INITIAL); return blifparse::Parser::make_DOT_SUBCKT(); }
<*>\.inputs                     { BEGIN(INITIAL); return blifparse::Parser::make_DOT_INPUTS(); }
<*>\.outputs                    { BEGIN(INITIAL); return blifparse::Parser::make_DOT_OUTPUTS(); }
<*>\.end                        { BEGIN(INITIAL); return blifparse::Parser::make_DOT_END(); }
<*>\.blackbox                   { BEGIN(INITIAL); return blifparse::Parser::make_DOT_BLACKBOX(); }

<*>\.conn                       { BEGIN(INITIAL); return blifparse::Parser::make_DOT_CONN(); /*BLIF extension */}
<*>\.attr                       { BEGIN(INITIAL); return blifparse::Parser::make_DOT_ATTR(); /*BLIF extension */}
<*>\.param                      { BEGIN(INITIAL); return blifparse::Parser::make_DOT_PARAM(); /*BLIF extension */}
<*>\.cname                      { BEGIN(INITIAL); return blifparse::Parser::make_DOT_CNAME(); /*BLIF extension */}


=                               { return blifparse::Parser::make_EQ();}
<LATCH>fe                       { return blifparse::Parser::make_LATCH_FE(); }
<LATCH>re                       { return blifparse::Parser::make_LATCH_RE(); }
<LATCH>ah                       { return blifparse::Parser::make_LATCH_AH(); }
<LATCH>al                       { return blifparse::Parser::make_LATCH_AL(); }
<LATCH>as                       { return blifparse::Parser::make_LATCH_AS(); }
<LATCH>NIL                      { return blifparse::Parser::make_NIL(); }
<LATCH>0                        { return blifparse::Parser::make_LOGIC_FALSE(); }
<LATCH>1                        { return blifparse::Parser::make_LOGIC_TRUE(); }
<LATCH>2                        { return blifparse::Parser::make_LATCH_INIT_2(); }
<LATCH>3                        { return blifparse::Parser::make_LATCH_INIT_3(); }
<LATCH>{ENDL}                   {
                                  /*
                                   * Latches are only every defined on a single line,
                                   * so when we see the end of a line while in the LATCH
                                   * state we can go back to the regular (INITIAL) state.
                                   */
                                  BEGIN(INITIAL); return blifparse::Parser::make_EOL();
                                }
<SO_COVER>0                     { return blifparse::Parser::make_LOGIC_FALSE(); }
<SO_COVER>1                     { return blifparse::Parser::make_LOGIC_TRUE(); }
<SO_COVER>\-                    { return blifparse::Parser::make_LOGIC_DONT_CARE(); }
<SO_COVER>{ENDL}                { return blifparse::Parser::make_EOL(); }
<NAMES>{ENDL}                   {
                                  /*
                                   * Once we reach the end of a line in NAMES state (i.e. the end of a .names line)
                                   * we expect the truth table (in single output cover format) to follow, so we enter
                                   * the SO_COVER state.
                                   */
                                  BEGIN(SO_COVER);
                                  return blifparse::Parser::make_EOL();
                                }
<INITIAL,NAMES,LATCH>([\"][^\r\n\"]*[\"])|(({ID_SET}|{BACK_SLASH})*{ID_SET}) {
                                    /*
                                     * There two types of STRING's this
                                     * expression recognizes:
                                     *  - Quoted strings, with no string
                                     *    escape allowed, no line continuation
                                     *    allowed.
                                     *  - Unquoted strings.
                                     *
                                     * For the unquoted strings, we allow all
                                     * sorts of characters in regular strings.
                                     * However we need to be careful about line continuations
                                     * in particular, it is possible that we could have a string
                                     * followed by a continuation with no space for this reason,
                                     * we do not allow a continuation (backslash, \\ in escaped
                                     * form in the regex) in the last character of the string.
                                     */
                                    return blifparse::Parser::make_STRING(blifparse_get_text(yyscanner));
                                }
<<EOF>>                         { /* If the file has no blank line at the end there will
                                     not be the expected EOL following the last command.
                                     So first time through, return EOL, and subsequently
                                     return 0 (which indicated end of file). This ensures
                                     there will always be an EOL provided to the parser.
                                     However it may also generate a stray EOL if the last
                                     line IS blank - so the parser must handle those correclty. */
                                  static bool once; return (once = !once) ? blifparse::Parser::make_EOL() : blifparse::Parser::make_EOF();
                                }
<*>.                            { blifparse::blif_error_wrap(callback, blifparse_get_lineno(yyscanner), blifparse_get_text(yyscanner), "Unrecognized character"); }
%%
